

import javax.vecmath.Vector3d;
import java.util.List;
import java.util.Vector;

/**
 * Die Klasse Koerper haelt die Informationen eines Himmelskoerpers, mit diversen
 * Methoden koennen Kraft, Beschleunigung und Geschwindigkeit ausgerechnet werden
 * die ein anderer Koerper auf diesen Koerper ausuebt. Zudem ist ein Attribut
 * vorhanden das die aktuelle Position des Koerpers festhaelt, sowie eine Liste
 * mit allen seinen bisherigen Positionen. Ausserdem werden in den Attributen
 * Masse, Radius und ID Informationen ueber den Koerper gehalten die unveraenderbar
 * sind.
 * 
 * @author r4smus
 */
public class Body {
	private final int id;
	private static int idCounter = 0;
	private final double radius;
	private final double mass;
	private Vector3d position;
	private Vector3d velocity = new Vector3d();
	private Vector3d acceleration;
	private Vector3d force;
	private static final double GRAVI_KONST = 6.673E-11;
	private Vector3d newPosition;

	public Body(double radius, double mass, Vector3d position) {
		this.radius = radius;
		this.mass = mass;
		this.position = position;
		idCounter++;
		id = idCounter;
		
	}
	
	/**
	 * Inititialisiert die Anfangsgeschwindigkeit eines Koerpers in Form eines Vektors.
	 * Ohne ein MultiBodySystem kann die Anfangsgeschw. nicht berechnet werden, da sonst die Parameter fehlen
	 * 
	 * @param zentralGestirn
	 * @param simulationsRichtung (new Vektor3d(0,0,1) --> Planet bewegt sich gegen den Uhrzeigersinn)
	 */
	public void initStartVelocity(double totalMass, Vector3d totalMassPosition, Vector3d simulationDirection) {
		// zuerst den Betrag der Stargeschwindigkeit ausrechnen
		Vector3d velocityPos = (Vector3d)position.clone(); //velocityPos = Position K�rper - Position Punktmasse aller K�rper
		velocityPos.sub(totalMassPosition);
		double normVelocityPos = velocityPos.length();
		double normVelocity = (totalMass - mass) * Math.sqrt( (GRAVI_KONST * totalMass) * ( 1 / normVelocityPos ) ) * ( 1 / totalMass );
		// Vektor der Startgeschw. ausrechnen und dem Attribut zuweisen		
		velocity.cross(velocityPos, simulationDirection);
		double normStartVelocity = velocity.length();
		velocity.scale( normVelocity / normStartVelocity );		
	}

	/**
	 * Es wird die Gravitationskraft berechnet die 2 Koerper gegeneinander
	 * ausueben, anschlie�end wird die Kraft im Attribut kraft gespeichert.
	 * 
	 * @param k
	 * @return force
	 */
	private Vector3d calcForce(Body b) {
		double m1 = mass;
		double m2 = b.getMass();
		Vector3d r1 = position;
		Vector3d r2 = (Vector3d) b.getPosition().clone();

		r2.sub(r1);
		double r2_LengthSquared = r2.lengthSquared();
		double r2_Length = r2.length();
		double d1 = (GRAVI_KONST * m1) * (m2 / (r2_LengthSquared));
		r2.scale(d1 / r2_Length);

		this.force = r2;
		return force;
	}

	/**
	 * Berechne die neue Geschwindigkeit(t+delta_t). Anfangsgeschw. = aktueller velocity wert
	 * 
	 * @param delta_t
	 * @return velocity (current velocity of the body)
	 */
	public Vector3d calcVelocity(double delta_t) {
		Vector3d tempA = (Vector3d) acceleration.clone();
		tempA.scale(delta_t);
		velocity.add(tempA);
		return velocity;
	}

	/**
	 * Berechnet die neue Position nach der Zeit delta_t und speichert sie im Attribut position
	 * im aktuellen Koerper.
	 * @param delta_t
	 */
	public Vector3d calcNewPos(int delta_t) {
		Vector3d tempV = (Vector3d) velocity.clone();
		Vector3d tempA = (Vector3d) acceleration.clone();
		Vector3d tempPos;
		tempV.scale(delta_t);
		position.add(tempV);
		tempA.scale((delta_t * delta_t) / 2);
		position.add(tempA);

		tempPos = (Vector3d) this.position.clone();
		return position;
	}

	/**
	 * Berechnung der Beschleunigung die ein Koerper k auf den aktuellen Koerper
	 * ausuebt. Kraft und Beschleunigung werden in den Attributen kraft und a
	 * gespeichert.
	 * 
	 * @param k
	 */
	public Vector3d calcAcceleration(Body b) {
		calcForce(b);
		Vector3d tempA = (Vector3d) force.clone(); // sonst das kraft attribu													// ver�ndert wird
		tempA.scale(1 / mass);
		this.acceleration = tempA;
		return acceleration;
	}

	/**
	 * Vergleicht 2 Koerper anhand ihrer ID.
	 */
	public boolean equals(Object o) {
		if (o instanceof Body) {
			Body temp = (Body) o;
			if (temp.getId() == id)
				return true;
		}
		return false;
	}


			




	public int getId() {
		return id;
	}

	public double getMass() {
		return mass;
	}
	public void setPosition(Vector3d newPos) 
	{
		this.position.set(newPos) ;
	}
	public Vector3d getPosition() {
		return position;
	}

	public Vector3d getVelocity() {
		return velocity;
	}

	public Vector3d getAcceleration() {
		return acceleration;
	}

	public void setAcceleration(Vector3d a) {
		acceleration = a;
	}

	public String toString() {
		return "(ID: " +id +", mass: " + mass + ", radius: " + radius + ", position: "
		+ position   +")";
	}
	public void setNewPosition(Vector3d newPos) {
		this.newPosition = newPos;
		
	}
	public Vector3d getNewPosition() {
		// TODO Auto-generated method stub
		return newPosition;
	}

	public double getRadius(){
		return radius;
	}


	
}